# -*- coding: utf-8 -*-
import ast
import base64
import hashlib
import json
import random
import string
import time
from collections import OrderedDict

import requests
from django.conf import settings
from django.template import Context
from django.template.loader import get_template
from common.utils.qr import make_code
from async import async_job
from common.cache import redis_cache
from common.channel.pay import check_channel_order
from common.order import db as order_db
from common.order.model import PAY_STATUS
from common.utils import track_logging
from common.utils.exceptions import ParamError
from common.utils.ip_address import check_valid_ip_address

_LOGGER = track_logging.getLogger(__name__)

APP_CONF = {
    '101660': {
        # 盛大支付 支付宝H5、扫码 3% 50-50000 dwc
        'API_KEY': '4436ca24ba2a64726c6c074206ffe8d8',
        'gateway': 'http://api.newsendapay.com/v1/com/quartet/api/order/uniteCreate',
        'query_gateway': 'http://api.newsendapay.com/v1/com/quartet/api/order/query',
    },
}


def _get_api_key(mch_id):
    return APP_CONF[mch_id]['API_KEY']


def _get_gateway(mch_id):
    return APP_CONF[mch_id]['gateway']


def _get_query_gateway(mch_id):
    return APP_CONF[mch_id]['query_gateway']


def _gen_sign(s):
    m = hashlib.md5()
    m.update(s.encode('utf8'))
    sign = m.hexdigest().upper()
    return sign


def generate_sign(parameter, key):
    s = ''
    for k in sorted(parameter.keys()):
        if parameter[k] != '':
            s += '%s=%s&' % (k, parameter[k])
    s += 'key=%s' % key
    return _gen_sign(s)


def verify_notify_sign(params, key):
    sign = params['sign']
    params.pop('sign')
    calculated_sign = generate_sign(params, key)
    if sign.lower() != calculated_sign.lower():
        _LOGGER.info("shengdapay sign: %s, calculated sign: %s", sign, calculated_sign)
        raise ParamError('sign not pass, data: %s' % params)


def _get_pay_type(service):
    if service == 'alipay_h5':
        return '100001'
    elif service == 'alipay_scan':
        return '100001'
    elif service == 'wechat':
        return '100002'
    return '100001'


def _get_device_ip(info):
    try:
        extra = json.loads(info['extra'])
    except:
        extra = {}
    user_info = extra.get('user_info', {})
    return user_info.get('device_ip') or '127.0.0.1'


def _get_random_string():
    return ''.join(random.sample(string.ascii_letters + string.digits, 11))


def create_charge(pay, pay_amount, info):
    service = info.get('service')
    app_id = info['app_id']
    api_key = _get_api_key(app_id)
    parameter_dict = OrderedDict((
        ('merch_id', app_id),
        ('version', '10'),
        ('signtype', '0'),
        ('timestamp', str(int(round(time.time() * 1000)))),
        ('norce_str', _get_random_string()),
        ('detail', 'charge'),
        ('out_trade_no', str(pay.id)),
        ('money', str(int(pay_amount * 100))),
        ('channel', _get_pay_type(service)),
        ('callback_url', '{}/pay/api/{}/shengdapay/{}'.format(settings.NOTIFY_PREFIX, settings.NOTIFY_PATH, app_id)),
        ('ip', _get_device_ip(info)),
    ))
    parameter_dict['sign'] = generate_sign(parameter_dict, api_key)
    _LOGGER.info("shengdapay create: %s, order_id is: %s", json.dumps(parameter_dict), parameter_dict['out_trade_no'])
    headers = {"Content-type": "application/x-www-form-urlencoded"}
    response = requests.post(_get_gateway(app_id), data=parameter_dict, headers=headers, timeout=5)
    _LOGGER.info('shengdapay create rsp: %s', response.text)
    body = ast.literal_eval(base64.b64decode(json.loads(response.text)['body']))
    _LOGGER.info('shengdapay create rsp body: %s', body)
    if service == 'alipay_h5':
        return {'charge_info': body['payurl']}
    elif service == 'alipay_scan':
        template_data = {'base64_img': make_code(body['payurl']), 'amount': pay_amount}
        t = get_template('qr_alipay_shengdapay.html')
        html = t.render(Context(template_data))
        cache_id = redis_cache.save_html(pay.id, html)
        _LOGGER.info("wenfupay create_url: %s, pay.id: %s", settings.PAY_CACHE_URL + cache_id, pay.id)
        return {'charge_info': settings.PAY_CACHE_URL + cache_id}
    else:
        return {'charge_info': body['payurl']}


# SUCCESS
def check_notify_sign(request, app_id):
    api_key = _get_api_key(app_id)
    data = dict(request.POST.iteritems())
    _LOGGER.info("shengdapay notify data is: %s", data)
    verify_notify_sign(data, api_key)
    pay_id = data['out_trade_no']
    check_valid_ip_address(str(request.META['REMOTE_ADDR']), pay_id)
    if not pay_id:
        _LOGGER.error("fatal error, out_trade_no not exists, data: %s" % data)
        raise ParamError('shengdapay event does not contain pay ID')

    pay = order_db.get_pay(int(pay_id))
    if not pay:
        raise ParamError('pay_id: %s invalid' % pay_id)
    if pay.status != PAY_STATUS.READY:
        raise ParamError('pay %s has been processed' % pay_id)

    mch_id = pay.mch_id
    trade_status = str(data['status'])
    total_fee = float(data['paymoney']) / 100.0
    trade_no = str(data['orderid'])
    extend = {
        'trade_status': trade_status,
        'trade_no': trade_no,
        'total_fee': total_fee
    }
    check_channel_order(pay_id, total_fee, app_id)
    # 订单状态:
    # 0.待支付
    # 1.已支付
    # 2.系统补单
    # 3.商户补单
    # 4.已超时
    # 5.已取消
    # 6.其他
    if trade_status in ['1', '2'] and total_fee > 0.0:
        _LOGGER.info('shengdapay check order success, mch_id:%s pay_id:%s' % (mch_id, pay_id))
        order_db.add_pay_success(mch_id, pay_id, total_fee, trade_no, extend)
        # async notify
        async_job.notify_mch(pay_id)


def query_charge(pay_order, app_id):
    ''' 查询订单 '''
    api_key = _get_api_key(app_id)
    parameter_dict = OrderedDict((
        ('merch_id', app_id),
        ('version', '10'),
        ('signtype', '0'),
        ('timestamp', str(int(round(time.time() * 1000)))),
        ('norce_str', _get_random_string()),
        ('out_trade_no', str(pay_order.id)),

    ))
    parameter_dict['sign'] = generate_sign(parameter_dict, api_key)
    _LOGGER.info('shengdapay query data: %s, order_id is: %s', json.dumps(parameter_dict), str(pay_order.id))
    headers = {'Content-Type': 'application/x-www-form-urlencoded'}
    response = requests.post(_get_query_gateway(app_id), data=parameter_dict, headers=headers, timeout=5)
    _LOGGER.info('shengdapay query rsp, %s', response.text)
    if response.status_code == 200:
        data = ast.literal_eval(base64.b64decode(json.loads(response.text)['body']))
        _LOGGER.info("shengdapay query response body: %s", data)
        mch_id = pay_order.mch_id
        trade_status = str(data['status'])
        total_fee = float(data['money']) / 100.0
        trade_no = str(data['orderid'])
        extend = {
            'trade_status': trade_status,
            'total_fee': total_fee,
            'trade_no': trade_no,
        }
        # 订单状态：
        # 0.待支付
        # 1.已支付
        # 2.系统补单
        # 3.商户补单
        # 4.已超时
        # 5.已取消
        # 6.其他
        if trade_status in ['1', '2'] and total_fee > 0.0:
            pay_id = str(pay_order.id)
            check_channel_order(pay_id, total_fee, app_id)
            _LOGGER.info('shengdapay query order success, mch_id:%s pay_id:%s' % (mch_id, pay_order.id))
            order_db.add_pay_success(pay_order.mch_id, pay_order.id,
                                     total_fee, trade_no, extend)
            async_job.notify_mch(pay_order.id)
